package cn.com.haopy.dataes.es.utils;

import cn.com.haopy.dataes.es.entity.MetaDataField;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.*;
import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.cluster.metadata.MappingMetadata;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;

public class ESUtils {
    //分片数量
    public static int number_of_shards = 5;
    //备份数量
    public static int number_of_replicas = 0;
    //客户端对象
    public static RestHighLevelClient client = null;
    public static String host = "127.0.0.1";
    public static String port = "9200";

    //构造方法进行初始化
    public ESUtils() {
        List<HttpHost> nodes = new ArrayList<>();
        //添加集群中各节点对象到集合，主要是各节点的IP和端口，**这里只添加了一个节点**
        nodes.add(new HttpHost(host, Integer.parseInt(port), "http"));
        //初始化es客户端对象
        RestClientBuilder builder = RestClient.builder(nodes.toArray(new HttpHost[0]));
        client = new RestHighLevelClient(builder);
    }

    /**
     * 创建索引
     *
     * @param name 索引名称
     * @return
     */
    public boolean createIndex(String name) {
        try {
            CreateIndexRequest request = new CreateIndexRequest(name);

            request.settings(Settings.builder()
                    .put("index.number_of_shards", number_of_shards)
                    .put("index.number_of_replicas", number_of_replicas)
            );

            //同步执行
            RequestOptions options = RequestOptions.DEFAULT.toBuilder().build();

            CreateIndexResponse response = client.indices().create(request, options);

            System.out.println(response);


            System.out.println("索引创建完成");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public Map<String, List<AliasMetadata>> indices(String index) throws IOException {
        //创建查询对象
        GetIndexRequest request = new GetIndexRequest(index);
        RequestOptions options = RequestOptions.DEFAULT.toBuilder().build();
        GetIndexResponse response = client.indices().get(request, options);
        return response.getAliases();

    }

    /**
     * 判断索引是否存在
     *
     * @param name 索引名称
     * @return 执行结果
     */
    public boolean isExistIndex(String name) {
        try {
            //创建查询对象
            GetIndexRequest request = new GetIndexRequest(name);
            RequestOptions options = RequestOptions.DEFAULT.toBuilder().build();
            boolean exists = client.indices().exists(request, options);
            return exists;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除指定名称的索引
     *
     * @param name 索引名称
     * @return 执行结果
     */
    public boolean deleteIndex(String name) {
        try {
            DeleteIndexRequest request = new DeleteIndexRequest(name);
            RequestOptions options = RequestOptions.DEFAULT.toBuilder().build();
            client.indices().delete(request, options);
            System.out.println("删除了索引：" + name);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    public Boolean creatIndexType(String indexName, String type, List<MetaDataField> metaDataFields) {
        try {
            CreateIndexRequest request = new CreateIndexRequest(indexName);


            XContentBuilder xContentBuilder = jsonBuilder();

            xContentBuilder.startObject()
                    .startObject("mappings")
                    //.startObject(type)
                    .startObject("properties");
            for (MetaDataField dataField : metaDataFields
            ) {
                xContentBuilder.startObject(dataField.getFieldName())
                        .field("type", dataField.getFieldDataType())
                        .field("store", dataField.getFieldIsStored())
                        .field("index", dataField.getFieldIsIndexed());
                if ("text".equals(dataField.getFieldDataType())) {
                    //xContentBuilder.field("analyzer", "ik_max_word");
                }
                xContentBuilder.endObject();

            }

            xContentBuilder
                    .endObject()
                    .endObject()
                    .endObject();
            request.source(xContentBuilder);

            request.settings(Settings.builder()
                    .put("index.number_of_shards", number_of_shards)
                    .put("index.number_of_replicas", number_of_replicas)
            );
            //同步执行
            RequestOptions options = RequestOptions.DEFAULT.toBuilder().build();

            CreateIndexResponse response = client.indices().create(request, options);

            System.out.println(response);

            System.out.println("索引创建完成");
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 用于在mappings中为指定的type添加字段(获取mappings)
     *
     * @param name 索引名
     */
    public Map<String, MappingMetadata> getMapping(String name) {
        try {
            GetMappingsRequest request = new GetMappingsRequest().indices(name);
            return client.indices().getMapping(request, RequestOptions.DEFAULT).mappings();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 用于在mappings中为指定的type添加字段(更新mappings)
     *
     * @param name          索引名
     * @param metaDataField 自己封装的属性对象
     */
    public boolean updateMapping(String name, String type, MetaDataField metaDataField) {
        boolean flag = true;
        try {
            PutMappingRequest request = new PutMappingRequest(name);
            XContentBuilder xContentBuilder = jsonBuilder();
            xContentBuilder.startObject()
                    .startObject(type)
                    .startObject("properties")
                    .startObject(metaDataField.getFieldName())
                    .field("type", metaDataField.getFieldDataType())
                    .field("store", metaDataField.getFieldIsStored())
                    .field("index", metaDataField.getFieldIsIndexed());
            if ("text".equals(metaDataField.getFieldDataType())) {
                xContentBuilder.field("analyzer", "ik_max_word");
            }
            xContentBuilder.endObject()
                    .endObject()
                    .endObject()
                    .endObject();
            request.source(xContentBuilder);
            client.indices().putMapping(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            flag = false;
            e.printStackTrace();
        } finally {
            return flag;
        }
    }

    /**
     * 根据id值查询指定的文档
     *
     * @param indexName 索引库名称
     * @param id        id
     * @return 对应的文档字符串
     */
    public Map<String, Object> getDocumentById(String indexName, String id) {
        Map<String, Object> result = null;
        try {
            SearchRequest request = new SearchRequest(indexName);
            request.source().query(QueryBuilders.idsQuery().addIds(id));
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            if (response.getHits().getTotalHits().value > 0) {
                result = response.getHits().getAt(0).getSourceAsMap();
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return result;
        }
    }

    /**
     * 根据id批量查询文档
     *
     * @param name 索引库名称
     * @param ids  id值的数组
     * @return 对应文档的字符串集合
     */
    public List<String> getDocumentByIds(String name, String[] ids) {
        List<String> result = new ArrayList<>();
        try {
            SearchRequest request = new SearchRequest(name);
            request.source().query(QueryBuilders.idsQuery().addIds(ids));
            RequestOptions options = RequestOptions.DEFAULT.toBuilder().build();
            SearchResponse response = client.search(request, options);
            for (SearchHit document : response.getHits()) {
                result.add(document.getSourceAsString());
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return result;
        }
    }

    /**
     * 插入单个文档
     *
     * @param name 索引库名称
     * @param id   文档_id值
     * @param json 文档的json格式字符串
     * @return
     */
    public boolean insertOneByJson(String name, String id, String json) {
        boolean result = false;
        try {
            IndexRequest request = new IndexRequest(name).id(id).source(json, XContentType.JSON);
            RequestOptions options = RequestOptions.DEFAULT.toBuilder().build();
            client.index(request, options);
            result = true;
        } catch (Exception e) {

            e.printStackTrace();
        }
        return result;
    }

    public boolean insertOneByXbuilder(String name, String id, XContentBuilder xContentBuilder) {
        boolean result = false;
        try {
            IndexRequest request = new IndexRequest(name).id(id).source(xContentBuilder);
            client.index(request, RequestOptions.DEFAULT);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void main(String[] args) throws IOException {
        ESUtils esUtils = new ESUtils();
        //esUtils.createIndex("test");

       /* List<MetaDataField> list = new ArrayList<>();
        MetaDataField field = new MetaDataField();
        field.setFieldName("id");
        field.setFieldIsIndexed(true);

        list.add(field);

        field = new MetaDataField();
        field.setFieldName("name");
        field.setFieldIsIndexed(true);

        list.add(field);*/

        //esUtils.deleteIndex("test3");

        //System.out.println(esUtils.creatIndexType("test3", "pres", list));

        //Map<String, MappingMetadata> map = esUtils.getMapping("test3");
        //System.out.println(map);

        esUtils.deleteIndex("cms_admin_log");


    }


}
